// --------------------------------------------------------------------------------------------------------------------
// <copyright file="WaitTestActivity.cs" company="JDML Consulting Ltd.">
//   Copyright 2011 Photon Project - http://photon.codeplex.com
// </copyright>
// <summary>
//   Defines the WaitTestActivity type.
// </summary>
// --------------------------------------------------------------------------------------------------------------------

namespace Photon.Testing.Threading
{
    using System;
    using System.Diagnostics;

    public class WaitTestActivity : AsynchronousTestActivity
    {
        #region Fields

        private readonly Func<bool> _condition;
        private readonly int _timeout;
        private readonly string _errorMessage;
        private bool _isInitialized;
        private DateTime _initializedAt;

        #endregion

        public WaitTestActivity(Func<bool> condition, int timeout, string timeoutMessage)
        {
            #region Validate Arguments

            Guard.ArgumentNull("condition", condition);
            Guard.ArgumentLessThan("timeout", timeout, 0);

            #endregion

            _condition = condition;
            _timeout = timeout;
            _errorMessage = timeoutMessage;
        }

        public override void Execute()
        {
            if (_condition())
            {
                SetCompleted();
            }
            else if (!IsCompleted)
            {
                EnsureInitialized();
                if (HasTimedOut)
                {
                    SetCompleted();
                    ThrowTimeoutException();
                }
            }
        }

        private void EnsureInitialized()
        {
            if (!_isInitialized)
            {
                _isInitialized = true;
                _initializedAt = DateTime.Now;
            }
        }

        private void ThrowTimeoutException()
        {
            if (string.IsNullOrEmpty(_errorMessage))
            {
                throw new TimeoutException("Timout occured in WaitTestActivity.");
            }

            throw new TimeoutException(string.Format("Timout occured in WaitTestActivity: {0}", _errorMessage));
        }

        private bool HasTimedOut
        {
            get
            {
                if (Debugger.IsAttached)
                {
                    if (DateTime.Now.Subtract(_initializedAt).TotalMilliseconds > _timeout)
                    {
                        Debug.WriteLine("Has timed out");
                    }

                    return false;
                }

                return DateTime.Now.Subtract(_initializedAt).TotalMilliseconds > _timeout;
            }
        }

        public override void Reset()
        {
            _isInitialized = false;
            base.Reset();
        }
    }
}